Skip to content

Add DD_TRACE_OTEL_SEMANTICS_ENABLED for OTel HTTP semantic conventions#11652

Open
link04 wants to merge 6 commits into
masterfrom
maximo/http-otel-semantics
Open

Add DD_TRACE_OTEL_SEMANTICS_ENABLED for OTel HTTP semantic conventions#11652
link04 wants to merge 6 commits into
masterfrom
maximo/http-otel-semantics

Conversation

@link04

@link04 link04 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an opt-in flag DD_TRACE_OTEL_SEMANTICS_ENABLED (trace.otel.semantics.enabled, default false) that makes HTTP server and client spans emit OpenTelemetry HTTP semantic-convention attribute names and span names instead of the Datadog ones. When enabled, only the OTel attribute set is emitted (the Datadog names are replaced, not added alongside).

Scope: HTTP only. Based on the OTel HTTP spans spec.

Behavior

Flag OFF (Datadog) Flag ON (OTel)
span name (resource) GET /route GET {route} (route appended when known; GET otherwise)
method http.method http.request.method (+ _OTHER/http.request.method_original for unknown verbs)
url (server) http.url, http.query.string url.path, url.scheme, url.query
url (client) http.url url.full (credentials redacted), url.scheme
host http.hostname / peer.hostname server.address / server.port
status http.status_code http.response.status_code
client IP (server) http.client_ip / network.client.ip client.address / network.peer.address
user agent (server) http.useragent user_agent.original
error (error flag) error.type = status for error responses

Implementation notes

  • The flag is gated at the two shared base decorators (HttpServerDecorator, HttpClientDecorator), so it covers all HTTP integrations from one place.
  • Status code stays in the dedicated DDSpanContext field (so APM trace stats keep their status-code dimension); only the serialized key is renamed, centralized via Metadata.httpStatusKey and applied by the trace mappers (v0.4/v0.5/v1), OTLP, and the file dispatcher.
  • Shared OtelHttpSemantics helper for method normalization, url.full credential redaction, error.type, and default server.port.
  • Span name follows the spec: the URL path/404 is never used as the target.

Testing

Unit / serialization (all green on latest master):

  • HttpServerDecoratorTest (85), HttpClientDecoratorTest (68) — on/off attribute, span-name, method-_OTHER, error.type, redaction coverage.
  • DDSpanContextTest (58) — status-key selection follows the flag.
  • TraceMapperV0_4/V0_5/V1PayloadTest — serializer regression.

End-to-end (real agent + bytecode instrumentation + msgpack → dd-apm-test-agent), one HTTP client call, flag off then on:

flag=false : name=http.request resource="GET /"
  http.method=GET  http.url=http://localhost:8200/?demo=1  http.query.string=demo=1  http.status_code=200
flag=true  : name=http.request resource="GET"
  http.request.method=GET  url.full=http://localhost:8200/?demo=1  url.scheme=http
  server.address=localhost  server.port=8200  http.response.status_code=200

Verified mutually exclusive: with the flag on, all http.method/http.url/http.status_code are absent; with it off, all OTel names are absent.

Known follow-ups (out of scope here)

  • network.protocol.version — HTTP version isn't available at the shared decorator (per-integration plumbing).
  • OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS override knob for the known-methods list.
  • Client 5xx span error flag (DD CLIENT_ERROR_STATUSES is 4xx-only; error.type is set for 5xx but the error flag isn't).

🤖 Generated with Claude Code

Opt-in flag (off by default) that makes HTTP server and client spans emit
OpenTelemetry HTTP semantic-convention attribute names and span names instead
of the Datadog ones. When enabled, only the OTel attribute set is emitted.

- Config flag trace.otel.semantics.enabled wired through TraceInstrumentationConfig,
  ConfigDefaults, Config, and metadata/supported-configurations.json.
- HttpServerDecorator / HttpClientDecorator branch on the flag to emit
  http.request.method, url.path/url.scheme/url.query (server) or url.full (client),
  server.address/port, client.address, network.peer.address, user_agent.original,
  http.response.status_code, plus _OTHER method normalization + method_original,
  error.type for error responses, and url.full credential redaction.
- Span name follows the spec: "{method}" (route appended by route-based naming for
  servers); the URL path/404 is never used as the target.
- HTTP status code stays in the dedicated DDSpanContext field (so trace stats keep
  their status dimension); the serializer renames the emitted key to
  http.response.status_code via Metadata.httpStatusKey.
- Shared OtelHttpSemantics helper for method normalization, url redaction,
  error.type, and default server.port.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@link04 link04 self-assigned this Jun 15, 2026
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Pipelines

Fix all issues with BitsAI

⚠️ Warnings

🚦 1 Pipeline job failed

Check pull requests | Check pull requests   View in Datadog   GitHub Actions

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: fc601e0 | Docs | Datadog PR Page | Give us feedback!

@link04 link04 added the tag: ai generated Largely based on code generated by an AI or LLM label Jun 15, 2026
@link04

link04 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0734789dc5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

- Remove unused Tags.NETWORK_PROTOCOL_VERSION constant (deferred follow-up).
- url.full redaction now redacts only the credential components actually present
  (user@ -> REDACTED@, user:pass@ -> REDACTED:REDACTED@) instead of always implying
  a password; covered by a parameterized test.
- Document that url.query stays gated on the query-string toggle under OTel semantics
  (privacy/PII control) rather than emitting unconditionally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dd-octo-sts

dd-octo-sts Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 13.98 s 13.94 s [-0.6%; +1.1%] (no difference)
startup:insecure-bank:tracing:Agent 12.90 s 12.97 s [-1.4%; +0.3%] (no difference)
startup:petclinic:appsec:Agent 16.79 s 16.60 s [+0.1%; +2.2%] (maybe worse)
startup:petclinic:iast:Agent 16.72 s 16.81 s [-1.4%; +0.3%] (no difference)
startup:petclinic:profiling:Agent 16.56 s 16.78 s [-2.3%; -0.4%] (maybe better)
startup:petclinic:sca:Agent 16.34 s 16.10 s [-4.7%; +7.7%] (unstable)
startup:petclinic:tracing:Agent 15.59 s 15.61 s [-7.0%; +6.7%] (unstable)

Commit: fc601e0e · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

link04 and others added 4 commits June 16, 2026 01:06
- Client spans no longer emit url.scheme/url.path/url.query: clients use url.full
  only (url.scheme is opt-in and already contained in url.full).
- Honor DD_TRACE_HTTP_CLIENT_TAG_QUERY_STRING=false for url.full (strip query and
  fragment), matching the Datadog http.url behavior and the server-side gating.
- Under OTel semantics, mark client 4xx AND 5xx as errors so the error flag and
  error.type stay consistent (the Datadog default only marks 4xx).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per the OTel HTTP spec, when http.request.method resolves to _OTHER the span
name's method component MUST be the literal "HTTP", not the raw verb. Add
OtelHttpSemantics.spanNameMethod() and use it when naming server and client
spans, while the http.request.method=_OTHER tag and http.request.method_original
keep the raw value.

Verified against system-tests OTEL_SEMANTICS (DataDog/system-tests#7139): the
previously-gated Test_HttpServerOtelSemantics::test_other_method_span_name now
passes (19/19).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses the repo policy (no new Spock tests): the new OTel semantic-convention
logic now lives in the OtelHttpSemantics helper, covered by a JUnit5
OtelHttpSemanticsTest (method _OTHER normalization, "HTTP" span-name, url.full
credential redaction, query/fragment stripping, default server.port, error.type).
The Spock decorator test files are restored to their upstream state. The
decorator flag-gating integration is covered end-to-end by system-tests
(DataDog/system-tests#7139) and the serialized status-key rename by DDSpanContextTest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@link04 link04 marked this pull request as ready for review June 16, 2026 21:03
@link04 link04 requested review from a team as code owners June 16, 2026 21:03
@link04 link04 requested review from PerfectSlayer, jordan-wong, mtoffl01 and sarahchen6 and removed request for a team June 16, 2026 21:03
@dd-octo-sts

dd-octo-sts Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Hi! 👋 Thanks for your pull request! 🎉

To help us review it, please make sure to:

  • Add at least one type, and one component or instrumentation label to the pull request

If you need help, please check our contributing guidelines.

@link04 link04 added the inst: opentelemetry OpenTelemetry instrumentation label Jun 16, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc601e0e28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// honor the query-string opt-out (privacy/PII) just like the Datadog http.url path
urlFull = OtelHttpSemantics.withoutQueryAndFragment(urlFull);
}
span.setTag(Tags.URL_FULL, urlFull);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Suppress legacy peer tags in OTel client mode

With DD_TRACE_OTEL_SEMANTICS_ENABLED=true, every client request with a host still runs the unconditional onURI(span, url) immediately above this branch, and UriBasedClientDecorator.onURI sets legacy peer.hostname/peer.port before this code adds server.address/server.port. That means OTel client spans are not actually replacing the Datadog peer tags, so consumers see both naming schemes for the same endpoint; make the URI peer tagging OTel-aware or skip it in the OTel path.

Useful? React with 👍 / 👎.

Comment on lines +350 to +351
if (url.port() > 0) {
span.setTag(Tags.SERVER_PORT, url.port());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pair forwarded host with forwarded port

When a proxied request supplies X-Forwarded-Host (and possibly X-Forwarded-Port) and the local request URL has a different port, this OTel branch takes server.address from the forwarded host but server.port only from url.port(). The extracted forwarded port is already available on this context, so proxied requests can be reported as server.address=public.example with the internal listener port (or no port) instead of the original client-facing port.

Useful? React with 👍 / 👎.

writeSpanTag(buf, THREAD_NAME, metadata.getThreadName());
if (metadata.getHttpStatusCode() != null) {
writeSpanTag(buf, HTTP_STATUS, metadata.getHttpStatusCode());
writeSpanTag(buf, metadata.getHttpStatusKey(), metadata.getHttpStatusCode());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Encode OTel HTTP status as an integer

For OTLP export with the OTel semantics flag enabled, metadata.getHttpStatusKey() becomes http.response.status_code but this call still uses the UTF8BytesString overload, so the OTLP attribute is encoded as a string value. The stable OTel HTTP attribute is an integer, and numeric filters/aggregations will miss spans that set the status through setHttpStatusCode; write the status via the long/int attribute path when using the OTel key.

Useful? React with 👍 / 👎.

spanLinks);
}

public Metadata(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure the maintainers will have a better idea, but we might just want to add the UTF8BytesString httpStatusKey argument to the main constructor and update all its uses so we don't need to maintain two constructors

@PerfectSlayer PerfectSlayer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 notes: ‏I had a quick look and the changes do not look great design wise and performance wise. Are you sure this is ready for review?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

inst: opentelemetry OpenTelemetry instrumentation tag: ai generated Largely based on code generated by an AI or LLM

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants